page.tsx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. "use client";
  2. import { getShareLinkApi } from "@/api/config";
  3. import {
  4. getCommissionApi,
  5. getRegisterCountApi,
  6. getTotalCountApi,
  7. getWithdrawalApi,
  8. } from "@/api/summary";
  9. import { CommissionModel } from "@/app/[locale]/affiliate/component/TabsCom";
  10. import Table, { TableHeaderItem } from "@/components/Table";
  11. import TipsModal, { ModalProps } from "@/components/TipsModal";
  12. import { usePathname } from "@/i18n/routing";
  13. import { useUserInfoStore } from "@/stores/useUserInfoStore";
  14. import { server } from "@/utils/client";
  15. import { getToken } from "@/utils/Cookies";
  16. import { copyText, flatPoint } from "@/utils/methods";
  17. import { useRequest } from "ahooks";
  18. import { Mask, Toast } from "antd-mobile";
  19. import clsx from "clsx";
  20. import { useTranslations } from "next-intl";
  21. import Image from "next/image";
  22. import { FC, useEffect, useRef, useState } from "react";
  23. import "./page.scss";
  24. interface Props {}
  25. const RulesClient = () => {
  26. const t = useTranslations("cashback");
  27. const [rules, setRules] = useState<any>([]);
  28. const [visible, setVisible] = useState(false);
  29. const columns: TableHeaderItem[] = [
  30. {
  31. title: <div className={"text-center text-[#98a7b5]"}>Nivel Agente</div>,
  32. dataIndex: "agent_level",
  33. align: "center",
  34. render: (item: any) => (
  35. <div className={"text-[0.12rem] text-[#98a7b5]"}>{item?.agent_level}</div>
  36. ),
  37. },
  38. {
  39. title: <div className={"text-center text-[#98a7b5]"}>Apostas Validas</div>,
  40. dataIndex: "bet",
  41. align: "center",
  42. render: (item: any) => (
  43. <div className={"text-[0.12rem] text-[#98a7b5]"}>{item?.bet / 10000} Dez mil+</div>
  44. ),
  45. },
  46. {
  47. title: <div className={"text-center text-[#98a7b5]"}>Comissão</div>,
  48. dataIndex: "ratio",
  49. render: (item: any) => (
  50. <div className={"text-center text-[0.12rem] text-[#db922b]"}>
  51. {flatPoint(item?.ratio / 100)}
  52. <span className={"text-[#98a7b5]"}>%</span>
  53. </div>
  54. ),
  55. },
  56. ];
  57. const loadMore = async () => {
  58. return Promise.resolve();
  59. };
  60. const getCashBackApi = async () => {
  61. return server
  62. .request<any>({
  63. url: "/v1/api/user/get_user_config_agent_info",
  64. method: "post",
  65. })
  66. .then((res) => {
  67. return {
  68. rules: res.data || [],
  69. };
  70. })
  71. .catch((error) => {
  72. return {
  73. rules: [],
  74. last_period: { end_time: 0, start_time: 0 },
  75. next_period: {
  76. end_time: 0,
  77. start_time: 0,
  78. },
  79. amount: 0,
  80. bet: 0,
  81. status: "expired",
  82. };
  83. });
  84. };
  85. useEffect(() => {
  86. getCashBackApi().then((res) => {
  87. setRules(res.rules);
  88. });
  89. }, []);
  90. return (
  91. <div className={"text-[0.12rem]"}>
  92. <div className={"bg-[#0e1319] p-[0.0694rem]"}>
  93. <Table
  94. columns={columns}
  95. headerClassName={" bg-[#151d28] "}
  96. bodyClassName={"odd:bg-[#0e1319] even:bg-[#151d28]"}
  97. dataSource={rules || []}
  98. loadMore={loadMore}
  99. hasMore={false}
  100. isLoadMore={false}
  101. isBackground={false}
  102. />
  103. </div>
  104. <div className={"mt-[0.1389rem] flex items-center text-[#98a7b5]"}>
  105. <p
  106. className={"mr-[0.1389rem] h-[0.0694rem] w-[0.0694rem] rounded bg-[#98a7b5]"}
  107. ></p>{" "}
  108. A apostas válidas depende dos diferentes jogos:
  109. </div>
  110. <div className={"mt-[0.1389rem] flex bg-[#25262b] p-[0.1389rem] text-[#98a7b5]"}>
  111. <span className={"iconfont icon-tishi text-[0.10rem]"}></span>
  112. <div className={"ml-[0.0694rem]"}>
  113. Os tipos de crash e os jogos virtuais não serão considerados apostas válidas{" "}
  114. </div>
  115. </div>
  116. <div className={"mt-[0.1389rem] bg-[#25262b] p-[0.1389rem] text-[#98a7b5]"}>
  117. <div>
  118. <span className={"text-[0.22rem] text-[#fff]"}>100%</span>
  119. <span> De aposta </span>
  120. </div>
  121. <div>
  122. <span className={"text-[#575f6a]"}>Jogos : </span>
  123. <span> Live Casino, 3rd Party</span>
  124. </div>
  125. </div>
  126. <div className={"mt-[0.1389rem] bg-[#25262b] p-[20px] text-[#98a7b5]"}>
  127. <div>
  128. <span className={"text-[0.22rem] text-[#fff]"}>100%</span>
  129. <span> De aposta </span>
  130. </div>
  131. <div>
  132. <span className={"text-[#575f6a]"}>Jogos : </span>
  133. <span>Os outros jogos originais</span>
  134. </div>
  135. </div>
  136. <div
  137. onClick={() => setVisible(true)}
  138. className={
  139. "mt-[0.1389rem] flex justify-between bg-[#25262b] p-[0.1042rem] text-[#98a7b5]"
  140. }
  141. >
  142. Regras de cálculo de comissão
  143. <span className={"iconfont icon-xiangyou2"}></span>
  144. </div>
  145. <ul className={"ml-[0.1389rem] mt-[0.1389rem] list-disc text-[#98a7b5]"}>
  146. <li className={"mt-[0.0694rem]"}>
  147. As comissões podem ser retiradas em nossa carteira bcwin do painel a qualquer
  148. momento.
  149. </li>
  150. <li className={"mt-[0.0694rem]"}>O sistema calcula a comissão a cada 3 minutos.</li>
  151. <li className={"mt-[0.0694rem]"}>Comissão máxima diária : 10000 BRL</li>
  152. <li className={"mt-[0.0694rem]"}>
  153. A comissão não será creditada para o mesmo IP ou dispositivo, e a inflação
  154. intencional do volume de negócios não será creditada para a comissão.{" "}
  155. </li>
  156. </ul>
  157. <CommissionModel visible={visible} setVisible={setVisible} />
  158. </div>
  159. );
  160. };
  161. const App: FC<Props> = (props) => {
  162. const t = useTranslations("SummaryPage");
  163. const sliderRef = useRef<HTMLDivElement>(null);
  164. const pathname = usePathname();
  165. const [num, setNum] = useState(100);
  166. const [money, setMoney] = useState("5000");
  167. const [visible, setVisible] = useState(false);
  168. const [BASE_URL, setBaseUrl] = useState("");
  169. const todayModalRef = useRef<ModalProps>(null);
  170. const totalModalRef = useRef<ModalProps>(null);
  171. const { userInfo } = useUserInfoStore();
  172. const token = getToken();
  173. // 生成分享链接
  174. // const BASE_URL = window.location.href.replace(pathname, "");
  175. const shareUrl = `${BASE_URL}?share_id=${userInfo ? userInfo.referrer_code : "xxxxxx"}`;
  176. const url = encodeURIComponent(`${shareUrl}`);
  177. const SHARE_SOURCE = [
  178. {
  179. icon: "/summary/Facebook.png",
  180. label: "Facebook",
  181. shareUrl: `https://www.facebook.com/sharer/sharer.php?u=${url}`,
  182. },
  183. {
  184. icon: "/summary/WhatsApp.png",
  185. label: "WhatsApp",
  186. shareUrl: `https://api.whatsapp.com/send?text=${url}`,
  187. },
  188. {
  189. icon: "/summary/Telegram.png",
  190. label: "Telegram",
  191. shareUrl: `https://t.me/share/url?url=${url}`,
  192. },
  193. {
  194. icon: "/summary/Twitter.png",
  195. label: "Twitter",
  196. shareUrl: `https://twitter.com/intent/tweet?text=${url}`,
  197. },
  198. {
  199. icon: "/summary/Email.png",
  200. label: "Email",
  201. shareUrl: `mailto: ?&subject=&cc=&bcc=&body=${url}`,
  202. },
  203. ];
  204. // 轮询时间
  205. const TIME = 180000;
  206. const getUserMoneyHandler = () => {
  207. if (token) {
  208. return getRegisterCountApi().then((res) => {
  209. if (res.code === 200) return res.data;
  210. });
  211. }
  212. return Promise.resolve({
  213. commissar: 0,
  214. effective_amount: 0,
  215. recharge_user_count: 0,
  216. reg_count: 0,
  217. });
  218. };
  219. const { data: todayData } = useRequest(getUserMoneyHandler, {
  220. pollingInterval: TIME,
  221. pollingErrorRetryCount: 3,
  222. staleTime: 5000,
  223. refreshDeps: [token],
  224. });
  225. const getTotalCount = () => {
  226. if (token) {
  227. return getTotalCountApi().then((res) => {
  228. if (res.code === 200) return res.data;
  229. });
  230. }
  231. return Promise.resolve({
  232. commissar: 0,
  233. effective_amount: 0,
  234. recharge_user_count: 0,
  235. reg_count: 0,
  236. });
  237. };
  238. const { data: totalData } = useRequest(getTotalCount, {
  239. pollingInterval: TIME,
  240. pollingWhenHidden: true,
  241. pollingErrorRetryCount: 3,
  242. staleTime: 5000,
  243. });
  244. const getCommission = () => {
  245. if (token) {
  246. return getCommissionApi().then((res) => {
  247. if (res.code === 200) return res.data;
  248. });
  249. }
  250. return Promise.resolve({
  251. commissar: 0,
  252. level: 0,
  253. withdrawal_commissions: 0,
  254. enable_receive: false,
  255. min_value: 0,
  256. max_value: 0,
  257. });
  258. };
  259. const { data: commissionData, run: commissionRun } = useRequest(getCommission, {
  260. pollingInterval: TIME,
  261. pollingErrorRetryCount: 3,
  262. staleTime: 5000,
  263. });
  264. const handleSlide: any = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
  265. if (sliderRef.current) {
  266. const startX = sliderRef.current.getBoundingClientRect().x;
  267. const x = e.clientX - startX;
  268. const xRem = x / (144 * 0.6);
  269. const intNum = Math.round(10000 * xRem) - Math.round((10000 * xRem) % 10);
  270. setNum(intNum);
  271. const m = intNum * 50;
  272. let r = "";
  273. const arr = m.toString().split("");
  274. arr.forEach((item, i) => {
  275. if (i !== arr.length - 1 && (arr.length - i - 1) % 3 === 0) {
  276. r += item + ",";
  277. } else {
  278. r += item;
  279. }
  280. });
  281. setMoney(r);
  282. const scale = (Math.round(xRem * 10000) / 100.0).toFixed(2) + "%";
  283. sliderRef.current.style.width = scale;
  284. }
  285. };
  286. const copy = (text: string) => {
  287. copyText(text);
  288. Toast.show({ icon: "success", content: t("copySuc"), maskClickable: false });
  289. };
  290. const withdrawalHandler = async () => {
  291. if (commissionData === undefined) return;
  292. if (!commissionData.enable_receive) {
  293. Toast.show(t("receive"));
  294. return;
  295. }
  296. const commissar = commissionData.commissar ?? 0; // 使用空值合并运算符处理可能的 undefined
  297. const minValue = Math.min(commissionData.min_value, 10);
  298. if (commissar > minValue) {
  299. const available = Math.min(commissionData.max_value, commissar);
  300. getWithdrawalApi({ amount: available }).then((res) => {
  301. if (res.code === 200) {
  302. setTimeout(commissionRun, 200);
  303. }
  304. });
  305. return;
  306. } else {
  307. Toast.show(t("receive"));
  308. }
  309. };
  310. useEffect(() => {
  311. getShareLinkApi().then((res) => {
  312. const url =
  313. res.data.find((item) => item.type === 2)?.url ??
  314. window.location.href.replace(pathname, "");
  315. setBaseUrl(url);
  316. });
  317. }, []);
  318. return (
  319. <div className="content">
  320. <div className="summary referral-router-view">
  321. <div className="content" style={{ marginTop: 0 }}>
  322. <div className="title">
  323. <div>
  324. {t("Hoje")}
  325. <span
  326. className="iconfont icon-bangzhu"
  327. onClick={() => todayModalRef.current?.onOpen()}
  328. />
  329. </div>
  330. </div>
  331. <div className="cardMian">
  332. <ul className="statistics-card">
  333. <li>
  334. <p className="num">{flatPoint(todayData?.reg_count ?? 0)}</p>
  335. <p> {t("Inscrições")} </p>
  336. </li>
  337. <li>
  338. <p className="num">
  339. {flatPoint(todayData?.recharge_user_count ?? 0)}
  340. </p>
  341. <p> {t("Novos")} </p>
  342. </li>
  343. <li>
  344. <p className="num">
  345. <span className={"mr-[5px]"}>{t("R$")}</span>
  346. {flatPoint(todayData?.effective_amount ?? 0)}
  347. </p>
  348. <p> {t("Aposta")} </p>
  349. </li>
  350. <li>
  351. <p className="num">
  352. <span className={"mr-[5px]"}>{t("R$")}</span>
  353. {flatPoint(todayData?.commissar ?? 0)}
  354. </p>
  355. <p> {t("Comissão")} </p>
  356. </li>
  357. </ul>
  358. </div>
  359. </div>
  360. <div className="content">
  361. <div className="title">
  362. <div>
  363. {t("Total")}
  364. <span
  365. className="iconfont icon-bangzhu"
  366. onClick={() => totalModalRef.current?.onOpen()}
  367. />
  368. </div>
  369. </div>
  370. <div className="cardMian">
  371. <ul className="statistics-card">
  372. <li>
  373. <p className="num">{flatPoint(totalData?.reg_count ?? 0)}</p>
  374. <p> {t("Inscrições")} </p>
  375. </li>
  376. <li>
  377. <p className="num">
  378. {flatPoint(totalData?.recharge_user_count ?? 0)}
  379. </p>
  380. <p> {t("Jogadores")} </p>
  381. </li>
  382. <li>
  383. <p className="num">
  384. <span className={"mr-[5px]"}>{t("R$")}</span>
  385. {flatPoint(totalData?.effective_amount ?? 0)}
  386. </p>
  387. <p> {t("ApostaTotal")} </p>
  388. </li>
  389. <li>
  390. <p className="num">
  391. <span className={"mr-[5px]"}>{t("R$")}</span>
  392. {flatPoint(totalData?.commissar ?? 0)}
  393. </p>
  394. <p>RS {t("Comissão")} </p>
  395. </li>
  396. </ul>
  397. </div>
  398. </div>
  399. <div className="content">
  400. <div className="title">
  401. <div>
  402. {t("Comissão")}
  403. <span
  404. className="iconfont icon-bangzhu"
  405. onClick={() => setVisible(true)}
  406. />
  407. </div>
  408. </div>
  409. <div className="cardMian">
  410. <div className="vip">
  411. <div className="level">
  412. {/*<span className="iconfont icon-vip"></span>*/}
  413. <Image
  414. src={"/summary/level.png"}
  415. alt={"level"}
  416. height={120}
  417. width={120}
  418. />
  419. <span className="levelNum">{commissionData?.level}</span>
  420. </div>
  421. <div>
  422. {t("Nível")}
  423. <span
  424. className="iconfont icon-tishi"
  425. onClick={() => setVisible(true)}
  426. ></span>
  427. </div>
  428. </div>
  429. <div>
  430. <ul className="commission">
  431. <li>
  432. <p className="num">
  433. <span>{t("R$")}</span>
  434. <span className="cash">
  435. {flatPoint(commissionData?.withdrawal_commissions ?? 0)}
  436. </span>
  437. </p>
  438. <p> {t("TotalPago")} </p>
  439. </li>
  440. <li>
  441. <p className="num">
  442. <span>{t("R$")}</span>
  443. <span className="cash">
  444. {flatPoint(commissionData?.commissar ?? 0)}
  445. </span>
  446. </p>
  447. <p> {t("Não")} </p>
  448. </li>
  449. </ul>
  450. <div className="wallet">
  451. <div
  452. className={clsx(
  453. "btn",
  454. !commissionData?.enable_receive ? "btn-disable" : ""
  455. )}
  456. onClick={withdrawalHandler}
  457. >
  458. {t("TRANSFERIR")}
  459. </div>
  460. <div className="tip">
  461. <span className="iconfont icon-tishi1"></span>
  462. {t("Valor")}
  463. </div>
  464. </div>
  465. </div>
  466. </div>
  467. </div>
  468. <div className="content shareMain">
  469. <div className="title">
  470. <div>{t("title1")}</div>
  471. </div>
  472. <div className="share">
  473. <ul className="sharePlatform">
  474. {SHARE_SOURCE.map((item, index) => {
  475. return (
  476. <a
  477. href={item.shareUrl}
  478. key={index}
  479. target={"_blank"}
  480. className={"flex flex-col items-center"}
  481. >
  482. <Image
  483. src={item.icon}
  484. alt={"Mais"}
  485. width={70}
  486. height={70}
  487. />
  488. <p className={"mt-[0.0347rem] text-[12px] text-[#808080]"}>
  489. {item.label}
  490. </p>
  491. </a>
  492. );
  493. })}
  494. </ul>
  495. </div>
  496. <div className="shareLink">
  497. <div className="">{t("content1")}</div>
  498. <div className="copyUrl">
  499. <span className="url omitWrap">{shareUrl}</span>
  500. <span id="copy" onClick={() => copy(shareUrl)}>
  501. {t("Cópia")}
  502. </span>
  503. </div>
  504. </div>
  505. </div>
  506. <div className="content">
  507. <div className="title">
  508. <div> {t("title2")}</div>
  509. </div>
  510. <div>
  511. <div className="tel-box">
  512. <a href="" className="telicon">
  513. <Image
  514. src="/summary/telegram-nobg.png"
  515. height={100}
  516. width={100}
  517. alt="telegram"
  518. />
  519. </a>
  520. <div className="hintTitle3">{t("content2-1")}</div>
  521. </div>
  522. <div className="hintTitle2">
  523. <i className="iconfont icon-tishi"></i>
  524. {t("content2-2")}
  525. <a
  526. href="https://t.me/jogobcwinOfficialChanel"
  527. target={"_blank"}
  528. style={{
  529. borderBottom: "1px solid rgb(109, 155, 195)",
  530. color: "#0000EE",
  531. }}
  532. >
  533. {t("business")}
  534. </a>
  535. </div>
  536. </div>
  537. </div>
  538. <div className="content">
  539. <div className="title">
  540. <div>
  541. {t("title3")}
  542. <span
  543. className="iconfont icon-bangzhu"
  544. onClick={() => setVisible(true)}
  545. ></span>
  546. </div>
  547. </div>
  548. <div className="hint">
  549. <div className="hintTitle">{t("content3")}</div>
  550. <div className="imgContent">
  551. <Image width={100} height={100} src="/summary/money.png" alt="" />
  552. <div>
  553. {t("number")}
  554. {num}
  555. <br />
  556. {t("Comissão")} &gt; {t("R$")} {money} {t("money")}
  557. </div>
  558. <div
  559. className="slider van-slider"
  560. style={{ height: "0.02rem" }}
  561. onClick={handleSlide}
  562. >
  563. <div
  564. className="van-slider__bar"
  565. style={{ width: "0.900901%", background: "rgb(0, 157, 128)" }}
  566. ref={sliderRef}
  567. >
  568. <div role="slider" className="van-slider__button-wrapper">
  569. <div className="img"></div>
  570. </div>
  571. </div>
  572. </div>
  573. </div>
  574. <div className="relationSchema">
  575. <div className="groupTitle">{t("title4")}</div>
  576. <img src="/summary/group_br.png" alt="" className="groupImg" />
  577. <ul className="rules">
  578. <li>
  579. {t("content4-1")}
  580. <span style={{ color: "red" }}>{t("red")}</span>.
  581. </li>
  582. <li>{t("content4-2")}</li>
  583. </ul>
  584. </div>
  585. </div>
  586. </div>
  587. <div className="content"></div>
  588. </div>
  589. <TipsModal title={t("modalTitle")} ref={todayModalRef}>
  590. <ul className={"list-decimal break-all p-[0.1389rem] pt-0 font-bold"}>
  591. <li>{t("todayDesc1")}</li>
  592. <li>{t("todayDesc2")}</li>
  593. <li>{t("todayDesc3")}</li>
  594. </ul>
  595. <p className={"text-[gray]"}>{t("modalTips")}</p>
  596. </TipsModal>
  597. <TipsModal title={t("modalTitle")} ref={totalModalRef}>
  598. <ul className={"list-decimal break-all p-[0.1389rem] pt-0 font-bold"}>
  599. <li>{t("totalDesc1")}</li>
  600. <li>{t("totalDesc2")}</li>
  601. <li>{t("totalDesc3")}</li>
  602. </ul>
  603. <p className={"text-[gray]"}>{t("modalTips")}</p>
  604. </TipsModal>
  605. <Mask visible={visible} getContainer={null}>
  606. <div className={"h-[100vh] w-[100%] overflow-scroll bg-[#1f2024]"}>
  607. <div
  608. className={
  609. "absolute top-0 flex items-center justify-between " +
  610. " h-[0.4167rem] w-[100%] border-[1px] bg-[#17181c] px-[0.1389rem]" +
  611. " z-10 border-[#666]"
  612. }
  613. >
  614. <p>Regras de recompensas por comissão</p>
  615. <i className={"iconfont icon-guanbi"} onClick={() => setVisible(false)}></i>
  616. </div>
  617. <div className={"mt-[0.4167rem] px-[0.1389rem] pt-[0.1389rem]"}>
  618. <RulesClient />
  619. </div>
  620. </div>
  621. </Mask>
  622. </div>
  623. );
  624. };
  625. export default App;